#include <set>
#include <list>
#include <deque>
#include <string>
#include <vector>
#include <iostream>
#include <functional>

namespace cpplinq
{
    
	////////////////////////////////////////////////////////////////
    // Exceptions
	////////////////////////////////////////////////////////////////
    class base_exception : std::exception
    {
	public:
		virtual const char* what ()  const throw ()
        {
            return "base_exception";
        }
    };
    class programming_error_exception : base_exception
    {
	public:
		virtual const char* what ()  const throw ()
        {
            return "programming_error_exception";
        }
    };
    class sequence_empty_exception : base_exception
    {
	public:
		virtual const char* what ()  const throw ()
        {
            return "sequence_empty_exception";
        }
    };

	////////////////////////////////////////////////////////////////
    // Enumerator
	// Enumerates the container using the InteratorPair
    ////////////////////////////////////////////////////////////////
    template<typename T, typename S>
    class ContainerEnumerator
    {
        std::function<T(S&)> _nextObject;
	    S _data;
				
    public:
	    typedef T value_type;
	
        ContainerEnumerator(std::function<T(S&)> nextObject, S data)
			: _nextObject(nextObject)
		    , _data(data)
        {
        }

		ContainerEnumerator(const ContainerEnumerator& _other)
			: _nextObject(_other._nextObject)
			, _data(_other._data)
		{
		}

        T next()
        {
            return _nextObject(_data);
        }
    };

    template<typename T, typename S>
    std::ostream & operator << (std::ostream & stream, ContainerEnumerator<T,S> enumerator)
    {
	    try
	    {
		    for (;;)
			    stream << enumerator.next() << ' ';
	    }
	    catch(sequence_empty_exception &) {}
	    return stream;
    }

    ////////////////////////////////////////////////////////////////
    // Iterator and Container pair
    ////////////////////////////////////////////////////////////////

    template<typename TI, typename TC>
    class IteratorContainerPair
    {
        std::function<TI(const TC &)> get_ti;

    public:
		TC second;
        TI first;
        
        IteratorContainerPair(const TC & tc, std::function<TI(const TC &)> get_ti)
			: get_ti(get_ti)
            , second(tc)
            , first(get_ti(second))
        {
        }

        IteratorContainerPair(const IteratorContainerPair<TI,TC> & pair)
            : get_ti(pair.get_ti)
            , second(pair.second)
            , first(get_ti(second))
        {
            for (auto it = pair.get_ti(pair.second); it != pair.first; ++it)
                first++;
        }
    };

}
